use std::error::Error;
use std::fs::File;
use std::io::{ErrorKind, Read};
use std::num::ParseIntError;
use std::{fs, io};

use crate::gen_title;

pub fn ch2_25_1() {
    gen_title("ch2_25_1", 18);

    let f = File::open("resources/hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("resources/hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file: {:?}", e),
            },
            other_error => panic!("Problem opening the file: {:?}", other_error),
        },
    };

    println!("Success!");
}

pub fn ch2_25_2() {
    gen_title("ch2_25_2", 18);

    fn read_username_from_file() -> Result<String, io::Error> {
        let f = File::open("resources/hello.txt");

        let mut f = match f {
            Ok(file) => file,
            Err(e) => return Err(e),
        };

        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => {
                println!("{}", s);
                Ok(s)
            }
            Err(e) => Err(e),
        }
    }

    read_username_from_file().expect("unable to read file");
}

pub fn ch2_25_3() {
    gen_title("ch2_25_3", 18);

    fn read_username_from_file() -> Result<String, io::Error> {
        let mut f = File::open("resources/hello.txt")?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        println!("{s}");
        Ok(s)
    }

    read_username_from_file().expect("unable to read file");
}

pub fn ch2_25_4() {
    gen_title("ch2_25_4", 18);

    fn read_username_from_file() -> Result<String, io::Error> {
        let mut s = String::new();

        File::open("resources/hello.txt")?.read_to_string(&mut s)?;
        println!("{s}");
        Ok(s)
    }

    read_username_from_file().expect("unable to read file");
}

pub fn ch2_25_5() {
    gen_title("ch2_25_5", 18);

    fn read_username_from_file() -> Result<String, io::Error> {
        fs::read_to_string("resources/hello.txt")
    }

    let result = read_username_from_file().expect("unable to read file");
    println!("{result}");
}

pub fn ch2_25_6() {
    gen_title("ch2_25_6", 18);

    fn first(arr: &[i32]) -> Option<&i32> {
        let v = arr.get(0)?;
        Some(v)
    }

    fn second(arr: &[i32]) -> Option<&i32> {
        arr.get(1)
    }

    println!("{:?}", first(&[1, 2, 3]));
    println!("{:?}", second(&[1, 2, 3]));
}

pub fn ch2_25_7() {
    gen_title("ch2_25_7", 18);

    fn last_char_of_first_line(text: &str) -> Option<char> {
        text.lines().next()?.chars().last()
    }

    println!("{:?}", last_char_of_first_line("hello world"));
}

pub fn ch2_25_8() -> Result<(), Box<dyn Error>> {
    gen_title("ch2_25_8", 18);

    let f = File::open("resources/hello.txt")?;

    println!("success");
    Ok(())
}

pub fn ch2_25_9() {
    gen_title("ch2_25_9", 18);

    macro_rules! r#try {
        ($e:expr) => {
            match $e {
                Ok(val) => val,
                Err(err) => return Err(::std::convert::From::from(err)),
            }
        };
    }

    println!("success");
}

pub fn ch2_25_pra_1() {
    gen_title("ch2_25_pra_1", 18);

    fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
        Ok(n1_str.parse::<i32>()? * n2_str.parse::<i32>()?)
    }

    let result = multiply("10", "2");
    println!("result: {:?}", result);
    assert_eq!(result.unwrap(), 20);

    let result = multiply("t", "2");
    println!("result: {:?}", result);
    assert_eq!(result.is_err(), true);

    println!("Success!");
}

pub fn ch2_25_pra_2() {
    gen_title("ch2_25_pra_2", 18);

    fn read_file1() -> Result<String, io::Error> {
        let f = File::open("resources/hello_not_exist.txt");
        let mut f = match f {
            Ok(file) => file,
            Err(e) => return Err(e),
        };

        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => Ok(s),
            Err(e) => Err(e),
        }
    }

    fn read_file2() -> Result<String, io::Error> {
        let mut s = String::new();

        File::open("resources/hello_not_exist.txt")?.read_to_string(&mut s)?;
        Ok(s)
    }

    assert_eq!(
        read_file1().unwrap_err().to_string(),
        read_file2().unwrap_err().to_string()
    );
    println!("Success!");
}

pub fn ch2_25_pra_3() {
    gen_title("ch2_25_pra_3", 18);

    fn add_two(n_str: &str) -> Result<i32, ParseIntError> {
        n_str.parse::<i32>().map(|n| n + 2)
    }

    assert_eq!(add_two("10").unwrap(), 12);
    println!("Success!");
}

pub fn ch2_25_pra_4() {
    gen_title("ch2_25_pra_4", 18);

    fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
        match n1_str.parse::<i32>() {
            Ok(n1) => match n2_str.parse::<i32>() {
                Ok(n2) => Ok(n1 * n2),
                Err(e) => Err(e),
            },
            Err(e) => Err(e),
        }
    }

    fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
        n1_str
            .parse::<i32>()
            .and_then(|n1| n2_str.parse::<i32>().map(|n2| n1 * n2))
    }

    fn print(result: Result<i32, ParseIntError>) {
        match result {
            Ok(n) => println!("n is {}", n),
            Err(e) => println!("Error: {}", e),
        }
    }

    let twenty = multiply1("10", "2");
    print(twenty);

    let tt = multiply("t", "2");
    print(tt);

    println!("Success!");
}

pub fn ch2_25_pra_5() {
    gen_title("ch2_25_pra_5", 18);

    type Res<T> = Result<T, ParseIntError>;

    fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> {
        Ok(first_number_str.parse::<i32>()? * second_number_str.parse::<i32>()?)
    }

    fn print(result: Res<i32>) {
        match result {
            Ok(n) => println!("n is {}", n),
            Err(e) => println!("Error: {}", e),
        };
    }

    print(multiply("10", "2"));
    print(multiply("t", "2"));

    println!("Success!");
}
